package symbol;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import translationTable.Method;

public class TranslationSymbolTable {
		
    private Map<String,SymbolTableEntry> symbols = new TreeMap<String, SymbolTableEntry>();

    private static TranslationSymbolTable instance;

    private String currentId;

    private int currentInstr = 0;

    private ObjectState lastObjectState;
    
    private String parentType;
    
    private Map<Integer,Integer> instructionFromMethodMap;
    
    private ArrayList<Method> methodsDescriptions;

    /**
        */
    private TranslationSymbolTable(SymbolTable st) {
        this.symbols = (Map<String, SymbolTableEntry>) ((HashMap<String, SymbolTableEntry>)st.getAll()).clone();
        this.currentId = st.getCurrentId();
        this.lastObjectState = st.getLastObjectState();
        this.parentType = st.getParentType();
        this.instructionFromMethodMap = st.getInstructionFromMethodMap();
        this.methodsDescriptions = st.getMethodsDescription();
    }

    public static TranslationSymbolTable getInstance(){
        if (null == instance) { // Premier appel
            instance = new TranslationSymbolTable(SymbolTable.getInstance());
        }
        return instance;
    }

    public ObjectState getLastObjectState() {
        return lastObjectState;
    }

    public void setLastObjectState(ObjectState lastObjectState) {
        this.lastObjectState = lastObjectState;
    }

    public int getCurrentInstr() {
        return currentInstr;
    }

    public void setCurrentInstr(int currentInstr) {
        this.currentInstr = currentInstr;
    }

    public void incrCurrentInstr(){
        ++this.currentInstr;
        //System.out.println("SymbolTable: currentInstr="+this.currentInstr);
    }

    public String getCurrentId() {
        return currentId;
    }

    public void setCurrentId(String currentId){
        this.currentId = currentId;
        //System.out.println("CURRENTID="+this.currentId);
    }

    public String getParentType() {
        return parentType;
    }

    public void setParentType(String parentType) {
        this.parentType = parentType;
    }
    
    /** 
        * Add a symbol in the table.
    */
    public void add(String identifier, SymbolTableEntry entry) {
        //System.out.println("New entry in the symbolTable: "+entry.toString()+"\n\n");
        this.symbols.put(identifier, entry);
    }

    /** Return the entry for the given lexeme.
        * 
        * @param lexeme
        * @return the entry, or <code>null</code> if not found.
        */
    public SymbolTableEntry get(String lexeme) {
            if (lexeme==null || lexeme.isEmpty()) return null;
            return this.symbols.get(lexeme);
    }

    public Map<String,SymbolTableEntry> getAll(){
        return this.symbols;
    }
    
    public void setSymbols(Map<String, SymbolTableEntry> m){
        this.symbols = (Map<String, SymbolTableEntry>) ((HashMap<String, SymbolTableEntry>)m).clone();
    }

    /** Return if the given lexeme is defined in the symbol table.
        * 
        * @param lexeme
        * @return the entry, or <code>null</code> if not found.
        */
    public boolean contains(String lexeme) {
            if (lexeme==null || lexeme.isEmpty()) return false;
            return this.symbols.containsKey(lexeme);
    }

    /** Clear the symbol table.
        */
    public void clear() {
            this.symbols.clear();
    }
    
     public int addMethodeDescription(Method myMethode){
        methodsDescriptions.add(myMethode);
        return methodsDescriptions.size()-1;
    }
    
    public void addCorrespondanceMethodeInstruction(Integer instruction, Integer indMethodeDescription){        
       instructionFromMethodMap.put(instruction, indMethodeDescription);
    }
    
        /**
         * 
         * @param m Methode Description
         
         * @return -1 si 'existe pas sinon retourne l'indexe dans la liste de methodeDescription
         */
    public Method getMethodeDescription(int numeroInstruction){            
        Method methode = null;
        if(this.instructionFromMethodMap.containsKey(numeroInstruction))
            methode = methodsDescriptions.get(this.instructionFromMethodMap.get(numeroInstruction));
        return methode;                
    }
    
    public void setMethodDescription(int inst, Method meth){
        this.methodsDescriptions.set(this.instructionFromMethodMap.get(inst), meth);
    }

    /**
        * {@inheritDoc}
        */
    @Override
    public  String toString() {
            StringBuilder b = new StringBuilder();
           /* for(SymbolTableEntry entry : this.symbols.values()) {
                    if (b.length()>0) {
                            b.append("\n"); //$NON-NLS-1$
                    }
                    b.append(entry.toString());
            }*/
            for(int i=0; i<this.methodsDescriptions.size(); i++) {
                    b.append(this.methodsDescriptions.get(i).toString());
            }
            b.append("\n parentType="+this.parentType);
            return b.toString();
    }
}